/*
 * Copyright 2011 Dominik Pretzsch <dominik.pretzsch at gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.blacksheep.jmoteextract.mvc.controller;

import de.blacksheep.jmoteextract.configuration.Configuration;
import de.blacksheep.jmoteextract.filesystem.CifsFileSystemView;
import de.blacksheep.jmoteextract.filesystem.FileChooser;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JTable;
import de.blacksheep.jmoteextract.mvc.model.MainModel;
import de.blacksheep.jmoteextract.mvc.view.MainView;
import java.util.logging.Logger;
import jcifs.smb.NtlmPasswordAuthentication;

/**
 * This is the controller used by the local GUI.
 * 
 * @author Dominik Pretzsch <dominik.pretzsch at gmail.com>
 */
public class MainController {
    
    private static final String TABLE_IN_NAME = "tableIn";
    private static final String POPUP_IN_NAME = "popupTableIn";
    
    private static final String TABLE_OUT_NAME = "tableOut";
    private static final String POPUP_OUT_NAME = "popupTableIn";
    
    private static final int CMD_DIALOG_EXTRACT  = 0;
    private static final int CMD_DIALOG_SETTINGS = 1;
    private static final int CMD_DIALOG_ABOUT    = 2;
    private static final int CMD_DIALOG_CRED     = 3;
    private static final int CMD_DIALOG_CONNECT  = 4;
    
    private static final int CMD_BUTTON_SERVER   = 50;
    private static final int CMD_BUTTON_CREDOK   = 51;
    private static final int CMD_BUTTON_CREDCA   = 52;
    private static final int CMD_BUTTON_CONNOK   = 53;
    
    private static final int CMD_CHKBOX_SERVER   = 100;
    
    /**
     * The main view.
     */
    private MainView _view;
    
    /**
     * The main model.
     */
    private MainModel _model;
    
    private static final Logger LOGGER =  Logger.getLogger(MainController.class.getName());
    
    public MainController(MainView view , MainModel model) {
        this._view = view;
        this._model = model;
        
        init();
    }
    
    private void init() {
        Configuration config = Configuration.getInstance();
        boolean serverActive = config.getBoolean(Configuration.PROP.USER, "serverActive");
        _view.getActiveServerCheckBox().setSelected(serverActive);
        _view.getActiveServerButton().setSelected(serverActive);
        
        registerListeners();
    }
    
    private void registerListeners() {
        _view.addTableInMouseListener(new TableMouseListener());
        _view.addTableOutMouseListener(new TableMouseListener());
        _view.addPopupInItemActionListeners(new PopupItemActionListener());
        _view.addPopupOutItemActionListeners(new PopupItemActionListener());
        _view.addFileMenuItemActionListeners(new CommandActionListener());
        _view.addExtrasMenuItemActionListeners(new CommandActionListener());
        _view.addHelpMenuItemActionListeners(new CommandActionListener());
        _view.addActiveServerButtonActionListener(new CommandActionListener());
        _view.addCredentialsDialogActionListener(new CommandActionListener());
        _view.addConnectServerDialogActionListener(new CommandActionListener());
    }
    
    // <editor-fold defaultstate="collapsed" desc="TableMouseListener: Handle Mouse Events For TableIn/TableOut">
    private class TableMouseListener extends MouseAdapter {
        
        private JTable source;
        private int row;
        private int col;
        
        private void determineSource(MouseEvent e) {
            this.source = (JTable) e.getSource();
        }
        
        private void determineCoords(MouseEvent e) {
            this.row = source.rowAtPoint(e.getPoint());
            this.col = source.columnAtPoint(e.getPoint());
        }
        
        private void correctRowSelection() {
            if (!source.isRowSelected(row))
                source.changeSelection(row, col, false, false);
        }
        
        private void showPopup(MouseEvent e) {
            if (TABLE_IN_NAME.equals(source.getName())) {
                _view.showTableInPopup(e.getComponent(), e.getX(), e.getY());
            } else if (TABLE_OUT_NAME.equals(source.getName())) {
                _view.showTableOutPopup(e.getComponent(), e.getX(), e.getY());
            }
        }
        
        @Override
        public void mouseReleased(MouseEvent e) {
            if (e.isPopupTrigger())
            {               
                determineSource(e);
                determineCoords(e);
                correctRowSelection();
                showPopup(e);
            }
        }      
    }
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc="PopupItemAction[...]: Listener And Strategies To Show Popups And Handle Events">
    private class PopupItemActionListener implements ActionListener {
        
        PopupItemActionContext context = null;
        
        private void determineContextFromActionCommand(String command) {
            if (command.startsWith(POPUP_IN_NAME)) {
                context = new PopupItemActionContext(new PopupItemActionStrategyTableIn());
            } else if (command.startsWith(POPUP_OUT_NAME)) {
                context = new PopupItemActionContext(new PopupItemActionStrategyTableOut());
            }
        }
        
        public void actionPerformed(ActionEvent e) {
            determineContextFromActionCommand(e.getActionCommand());               
            
            if (context != null) 
                context.actionPerformed(e);
        }        
    }
    
    interface PopupItemActionStrategy {
        void actionPerformed(ActionEvent e);
    }
    
    private class PopupItemActionContext {
        
        private PopupItemActionStrategy strategy;
        
        public PopupItemActionContext(PopupItemActionStrategy strategy) {
            this.strategy = strategy;
        }
        
        public void actionPerformed(ActionEvent e) {
            this.strategy.actionPerformed(e);             
        }
    }
    
    private class PopupItemActionStrategyTableIn implements PopupItemActionStrategy {
        
        private JTable table;
        
        // @TODO: private void determineItemFromCommand()
        // @TODO: private void callItemMethod()
        
        public void actionPerformed(ActionEvent e) {
            table = _view.getTableIn();
            int row = table.getSelectedRow();
        
            System.out.println("Item Nr:" + row);
        }        
    }
    
    private class PopupItemActionStrategyTableOut implements PopupItemActionStrategy {
        
        private JTable table;
        
        public void actionPerformed(ActionEvent e) {
            throw new UnsupportedOperationException("Not supported yet.");
        }        
    }
    // </editor-fold>
    
    // <editor-fold defaultstate="collapsed" desc="CommandActionListener: Listener And Event Handler For Menus And Dialogs">
    private class CommandActionListener implements ActionListener {
        
        private void determineAndCallMethodFromCommand(String command) {
            int cmd = -1;
            
            try {
                cmd = Integer.parseInt(command);
            } catch (NumberFormatException ex) {}
            
            switch (cmd) {
                case CMD_DIALOG_EXTRACT:
                    break;
                case CMD_DIALOG_SETTINGS:
                    break;
                case CMD_DIALOG_ABOUT:
                    break;
                case CMD_DIALOG_CRED:
                    showCredentialsDialog();
                    break;
                case CMD_DIALOG_CONNECT:
                    showConnectServerDialog();
                    break;
                case CMD_CHKBOX_SERVER:
                    setServerActiveProperty(false);
                    break;
                case CMD_BUTTON_SERVER:
                    setServerActiveProperty(true);
                    break;
                case CMD_BUTTON_CREDOK:
                    processCredentialsDialog(true);
                    break;
                case CMD_BUTTON_CREDCA:
                    processCredentialsDialog(false);
                    break;
                case CMD_BUTTON_CONNOK:
                    processConnectDialog();
                    break;
                default:
                    break;
            }
        }
        
        private void processConnectDialog() {            
            Object[] data = _view.getDataFromConnectServerDialog();
            String resource = (String) data[0];
            
            if (resource.isEmpty()) {
                return;
            }
            
            _view.showConnectServerDialog(false);
            
            //String hostAddr = _model.getServerName(resource);   
            //
            // TODO: How to know guest logon is really enabled?
            //       Windows returns successfull logon, even
            //       if guests can't access root-shares.
            //       False will be returned, if guest
            //       Account is deleted (disabled?), only.
            //NtlmPasswordAuthentication auth = 
            //            _model.obtainAuthorization(hostAddr, "GUEST", null);
            
            //if (auth == null) {
                showCredentialsDialog();
            //} else {
            //    showExtractDialog(hostAddr, auth);
            //}
        }
        
        private void processCredentialsDialog(boolean approved) {
            _view.showCredentialsDialog(false);
            if (approved) {               
                Object[] data = _view.getDataFromConnectServerDialog();
                String resource = (String) data[0];
                String hostAddr = _model.getServerName(resource);
                
                data = _view.getDataFromCredentialsDialog();
                String username = (String) data[0];
                String password = (String) data[1];
                
                NtlmPasswordAuthentication auth = 
                        _model.obtainAuthorization(hostAddr, username, password);
             
                if (auth != null) {                    
                    showExtractDialog(hostAddr, auth);
                } else {
                    _view.showCredentialsFailedMessage();
                }
            }
        }
        
        private void setServerActiveProperty(boolean wasButton) {
            Configuration config = Configuration.getInstance();
            boolean serverActive = true;
            
            if (wasButton) {
                serverActive = _view.getActiveServerButton().isSelected();
                _view.setActiveServerControlsSelected(serverActive);
            } else {
                serverActive = _view.getActiveServerCheckBox().isSelected();
                _view.setActiveServerControlsSelected(serverActive);
            }
            
            config.setProperty(Configuration.PROP.USER, 
                               "serverActive", 
                               String.valueOf(serverActive));
        }
        
        private void showExtractDialog(String hostAddr, 
                                       NtlmPasswordAuthentication auth) {
            
            CifsFileSystemView fsv = CifsFileSystemView.getFileSystemView();
            fsv.setServer(hostAddr);
            fsv.setAuth(auth);
                    
            Object[] data = _view.showExtractionDialog(fsv);
            FileChooser dialog = (FileChooser) data[0];
            int         option = (Integer)     data[1];
            
            if (option == FileChooser.APPROVE_OPTION) {
                String filePath = dialog.getSelectedFile().getAbsolutePath();              
                
                /*
                LOGGER.log(Level.FINE, "{0} is{1}a network path", new Object[]{absolutePath, _model.isRemotePath(absolutePath) ? " " : " not "});
                
                if (_model.isRemotePath(absolutePath)) {
                    _model.extractOnRemoteHost(absolutePath);
                }*/
                
                // As we use CIFS to connect to the remote file system
                // the path is proved to be a remote UNC path
                _model.extractOnRemoteHost(filePath);
            }
        }
        
        private void showConnectServerDialog() {
            _view.showConnectServerDialog(true);
        }
        
        private void showCredentialsDialog() {
            _view.showCredentialsDialog(true);
        }
        
        @Override
        public void actionPerformed(ActionEvent e) {
            determineAndCallMethodFromCommand(e.getActionCommand());
        }        
    }
    // </editor-fold>
}
